/*
 * Copyright (c) 2020-2021 imlzw@vip.qq.com jweb.cc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cc.jweb.adai.plugin.security;

import cc.jweb.boot.security.session.account.JwebSecurityAccount;
import cc.jweb.boot.security.session.perms.JwebPermsManager;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

import java.util.*;

/**
 * 数据库权限管理器
 */
public class DBPermsManager implements JwebPermsManager {

    // 角色缓存，提高查询效率
    private Map<String, List<String>> userRolesCache = new HashMap<>();
    // 权限缓存，提高查询效率
    private Map<String, List<String>> userPermsCache = new HashMap<>();

    public DBPermsManager() {

    }

    public List<String> getUserRoleWithCache(String userId) {
        List<String> roles = userRolesCache.get(userId);
        if (roles == null) {
            roles = new ArrayList<>();
            // 从数据库加载用户角色信息
            List<Record> rolesList = Db.find("SELECT sr.role_key FROM sys_role sr, sys_role_user sru WHERE sr.role_id = sru.role_id AND sru.user_id = ?", userId);
            if (rolesList != null) {
                for (Record role : rolesList) {
                    roles.add(role.get("role_key"));
                }
            }
            userRolesCache.put(userId, roles);
        }
        return roles;
    }

    public List<String> getUserPermsWithCache(String userId) {
        List<String> perms = userPermsCache.get(userId);
        if (perms == null) {
            perms = new ArrayList<>();
            // 加载用户权限
            List<Record> permsList = Db.find("SELECT DISTINCT (so.permission_key) FROM sys_role_user sru, sys_oper so, sys_role_oper sro WHERE sro.oper_id = so.oper_id AND sro.role_id = sru.role_id AND sru.user_id = ?", userId);
            if (permsList != null) {
                for (Record perm : permsList) {
                    perms.add(perm.getStr("permission_key"));
                }
            }
            userPermsCache.put(userId, perms);
        }
        return perms;
    }

    @Override
    public boolean hasRole(JwebSecurityAccount account, String role) {
        List<String> userRoleWithCache = getUserRoleWithCache(account.getUid());
        if (userRoleWithCache != null) {
            for (String roleKey : userRoleWithCache) {
                if (role.equals(roleKey)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean[] hasRoles(JwebSecurityAccount account, String... roles) {
        boolean[] booleans = new boolean[roles.length];
        List<String> userRoleWithCache = getUserRoleWithCache(account.getUid());
        for (int i = 0; i < roles.length; i++) {
            if (userRoleWithCache != null) {
                for (String roleKey : userRoleWithCache) {
                    if (roles[i].equals(roleKey)) {
                        booleans[i] = true;
                        break;
                    }
                }
            }
        }
        return booleans;
    }

    @Override
    public boolean hasAllRoles(JwebSecurityAccount account, String... roles) {
        boolean[] booleans = hasRoles(account, roles);
        for (boolean aBoolean : booleans) {
            if (!aBoolean) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean isPermitted(JwebSecurityAccount account, String permission) {
        List<String> userPermsWithCache = getUserPermsWithCache(account.getUid());
        if (userPermsWithCache != null) {
            for (String permsKey : userPermsWithCache) {
                if (permission.equals(permsKey)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean[] isPermitted(JwebSecurityAccount account, String... permissions) {
        boolean[] booleans = new boolean[permissions.length];
        List<String> userPermsWithCache = getUserPermsWithCache(account.getUid());
        for (int i = 0; i < permissions.length; i++) {
            if (userPermsWithCache != null) {
                for (String permsKey : userPermsWithCache) {
                    if (permissions[i].equals(permsKey)) {
                        booleans[i] = true;
                        break;
                    }
                }
            }
        }
        return booleans;
    }

    @Override
    public boolean isPermittedAll(JwebSecurityAccount account, String... permissions) {
        boolean[] booleans = isPermitted(account, permissions);
        for (boolean aBoolean : booleans) {
            if (!aBoolean) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void invalidate(JwebSecurityAccount account) {
        userRolesCache.remove(account.getUid());
        userPermsCache.remove(account.getUid());
    }
}
